#!/usr/bin/env python
# @file orders.py


import os
import sys

from object import Object

class PrimitiveCallable(Object):
    def __call__(self, context, name=None, *args):
        if not name:
            name = _('%s instance') % self.__class__.__name__
        return self.value(self, context, name, args)

    def __nonzero__(self):
        '''Instead of requiring people to wrap boolean expressions in an
        empty function, we just provide functions with a means to test their
        truth value by invoking them.'''

        # TODO: reveals a greater issue: how should we be passing around
        # context references?
        return bool(self(None))

    def __str__(self):
        return str(self())

    def evaluate(self):
        return self()

class Callable(PrimitiveCallable):
    def __call__(self, context, name, *args):
        raise NotImplementedError

class CmdException(Exception):
    pass

# Perhaps some automatic argument checking?
# We wouldn't have to pass "name" around anymore. The only reason that's
# used is for usage messages.

def pwd(self, context, name, args):
    if not args:
        context.write(os.getcwdu())
    else:
        raise CmdException, _('%s takes zero arguments') % name

def exit(self, context, name, args):
    if not args:
        raise SystemExit
    elif len(args) is 1:
        raise SystemExit, int(args[0].value)
    else:
        raise CmdException, _('%s takes zero or one arguments') % name

def logout(self, context, name, *args):
    if not args:
        raise SystemExit
    else:
        raise CmdException, _('%s takes zero arguments') % name

def vrx_if(self, context, name, args):
    '''If in Varix is implemented as an order. It syntax is:

        if EXPRESSION EXPRESSION (else EXPRESSION)?.

    It evaluates EXPRESSION as a boolean. If it evaluates True, its
    second argument is evaluated. Otherwise, if its third and fourth
    arguments are present, and its third argument's string value is
    'else', the fourth argument is evaluated. The value of the if block
    is the value of expression that is evaluated.

    '''

    if not args or (len(args) != 2 and len(args) != 4):
        raise CmdException, _('%s takes two or four arguments') % name
    if args[0]:
        return args[1].evaluate()
    elif len(args == 4) and str(args[2]) == 'else':
        return args[3].evaluate()

ORDERS = {
    'pwd': PrimitiveCallable(pwd),
    'logout': PrimitiveCallable(logout),
    'exit': PrimitiveCallable(exit),
    'if': PrimitiveCallable(vrx_if),
}
